package pers.cz.postgirl.core;

import pers.cz.postgirl.config.EvenType;
import pers.cz.postgirl.core.common.CpublicFuncCallBack;

import java.util.ArrayList;
import java.util.List;

/**
 * @program: postgirl-client
 * @description: 描述一个待增强的对象，其中待增强的方法，以及增强的位置
 * 1、如果使用javassist增强，则需要额外指定一个ctClass
 * @author: Cheng Zhi
 * @create: 2023-05-23 13:00
 **/
public class EnhanceModel {

    /**
     * 待增强类
     */
    private String classPattern;

    /**
     * 待增强方法
     */
    private MethodPattern[] methodPatterns;

    /**
     * 待增强描述的扩展信息。
     */
    private List<Event> events = new ArrayList<Event>();

    public EnhanceModel(String classPattern, MethodPattern[] methodPatterns) {
        this.classPattern = classPattern;
        this.methodPatterns = methodPatterns;

        for (MethodPattern methodPattern : methodPatterns) {

            for (EvenType evenType : methodPattern.getEvenTypes()) {
                Event event = null;
                switch (evenType) {
                    case BEFORE:
                        event = new BeforeEvent(this.getClass().getClassLoader(), classPattern, methodPattern.getMethodName(), methodPattern.getParamTypes(), methodPattern.getDefaultCodePattern(), evenType);
                        break;
                    case RETURN:
                        event = new ReturnEvent(this.getClass().getClassLoader(), classPattern, methodPattern.getMethodName(), methodPattern.getParamTypes(), methodPattern.getDefaultCodePattern(), evenType);
                        break;
                }

                if (event != null) {
                    events.add(event);
                }
            }
        }
     }

    public List<Event> getEvent() {
      return this.events;
    }
    public static EnhanceModel.EnhanceModelBuilder builder() {
        return new EnhanceModel.EnhanceModelBuilder();
    }

    public String getClassPattern() {
        return classPattern;
    }

    public MethodPattern[] getMethodPatterns() {
        return methodPatterns;
    }



    /**
     * 描述一个待增强方法
     */
    public static class MethodPattern {

        private String methodName;
        private String[] paramTypes;
        private String[] annotationTypes;
        /**
         * 观察的事件
         */
        private EvenType[] evenTypes;

        /**
         * 默认内容
         */
        private DefaultCodePattern defaultCodePattern;

        /**
         * 自定义插码内容，这里都用回调函数的方式
         */
        public static class DefaultCodePattern {

            private CpublicFuncCallBack beforeCodeFunc;
            private CpublicFuncCallBack returnCodeFunc;
            private CpublicFuncCallBack throwCodeFunc;

            public DefaultCodePattern(CpublicFuncCallBack beforeCodeFunc, CpublicFuncCallBack returnCodeFunc, CpublicFuncCallBack throwCodeFunc) {
                this.beforeCodeFunc = beforeCodeFunc;
                this.returnCodeFunc = returnCodeFunc;
                this.returnCodeFunc = returnCodeFunc;
            }

            public static DefaultCodePatternBuilder builder() {
                return new DefaultCodePatternBuilder();
            }
            public CpublicFuncCallBack getBeforeCode() {
                return beforeCodeFunc;
            }

            public CpublicFuncCallBack getReturnCode() {
                return returnCodeFunc;
            }

            public CpublicFuncCallBack getThrowCode() {
                return throwCodeFunc;
            }

            public static class DefaultCodePatternBuilder {
                private CpublicFuncCallBack beforeCodeFunc;
                private CpublicFuncCallBack returnCodeFunc;
                private CpublicFuncCallBack throwCodeFunc;

                public DefaultCodePatternBuilder beforeCode(CpublicFuncCallBack beforeCodeFunc) {
                    this.beforeCodeFunc = beforeCodeFunc;
                    return this;
                }

                public DefaultCodePatternBuilder returnCode(CpublicFuncCallBack returnCodeFunc) {
                    this.returnCodeFunc = returnCodeFunc;
                    return this;
                }

                public DefaultCodePatternBuilder throwCode(CpublicFuncCallBack throwCodeFunc) {
                    this.throwCodeFunc = throwCodeFunc;
                    return this;
                }

                public DefaultCodePattern build() {
                    return new DefaultCodePattern(this.beforeCodeFunc, this.returnCodeFunc, this.throwCodeFunc);
                }

            }
        }

        public MethodPattern(String methodName, String[] paramTypes, String[] annotationTypes, DefaultCodePattern defaultCodePattern, EvenType[] evenTypes) {

            this.methodName = methodName;
            this.paramTypes = paramTypes;
            this.annotationTypes = annotationTypes;
            this.evenTypes = evenTypes;
            this.defaultCodePattern = defaultCodePattern;
        }

        public static MethodPatternBuilder builder() {
            return new MethodPatternBuilder();
        }

        public String getMethodName() {
            return methodName;
        }

        public String[] getParamTypes() {
            return paramTypes;
        }

        public String[] getAnnotationTypes() {
            return annotationTypes;
        }

        public DefaultCodePattern getDefaultCodePattern() {
            return defaultCodePattern;
        }

        public EvenType[] getEvenTypes() {
            return evenTypes;
        }

        /**
         * 建造者
         */
        public static class MethodPatternBuilder {

            private String methodName;
            private String[] paramTypes;
            private String[] annotationTypes;
            private DefaultCodePattern defaultCodePattern;
            private EvenType[] evenTypes;

            public MethodPatternBuilder methodName(String methodName) {
                this.methodName = methodName;
                return this;
            }

            public MethodPatternBuilder paramTypes(String[] paramTypes) {
                this.paramTypes = paramTypes;
                return this;
            }

            public MethodPatternBuilder annotationTypes(String[] annotationTypes) {
                this.annotationTypes = annotationTypes;
                return this;
            }

            public MethodPatternBuilder content(DefaultCodePattern defaultCodePattern) {
                this.defaultCodePattern = defaultCodePattern;
                return this;
            }

            public MethodPatternBuilder evenTypes(EvenType[] evenTypes) {
                this.evenTypes = evenTypes;
                return this;
            }

            public MethodPatternBuilder defaultCodePattern(DefaultCodePattern defaultCodePattern) {
                this.defaultCodePattern = defaultCodePattern;
                return this;
            }
            public MethodPattern build() {
                return new MethodPattern(methodName, paramTypes, annotationTypes, defaultCodePattern, evenTypes);
            }

        }
    }

    /**
     * 建造者
     */
    public static class EnhanceModelBuilder {
        private String classPattern;
        private MethodPattern[] methodPatterns;
        private ClassLoader classLoader;

        public EnhanceModelBuilder() {

        }

        public EnhanceModelBuilder classPattern(String classPattern) {
            this.classPattern = classPattern;
            return this;
        }

        public EnhanceModelBuilder methodPatterns(MethodPattern[] methodPatterns) {
            this.methodPatterns = methodPatterns;
            return this;
        }

        public EnhanceModel build() {
            return new EnhanceModel(this.classPattern, this.methodPatterns);
        }
    }
}
